import type { IEntityDetail, IEntityInstance } from "@/typings/scenario-edit"
import type {
  Cartesian3,
  Viewer
} from "cesium"
import type {
  IDrawCallback,
  MouseHandler
} from "../CustomCesium/CustomCesium"
import {
  CallbackProperty,
  Cartesian2,
  Color,
  ConstantPositionProperty,
  ConstantProperty,
  createGuid,
  CustomDataSource,
  defined,
  Entity,
  HorizontalOrigin,
  JulianDate,
  LabelStyle
} from "cesium"
import _ from "lodash"
import {
  MathUtils
} from "../CustomCesium/CustomCesium"

// 绘制实体实例
export default class DrawEntityManager {
  private viewer: Viewer
  private mouseHandlerManager: MouseHandler
  readonly guid: string
  // 实体集合
  private drawEntities: CustomDataSource

  constructor(
    viewer: Viewer,
    mouseHandlerManager: MouseHandler,
    scnId: string
  ) {
    this.mouseHandlerManager = mouseHandlerManager
    this.guid = scnId
    // 已绘实体
    this.drawEntities = new CustomDataSource(`drawEntities_${this.guid}`)
    this.viewer = this.init(viewer)
  }

  private init(viewer: Viewer) {
    if (!defined(viewer)) throw new Error("EventListener,无效的视图对象！")
    viewer.dataSources.add(this.drawEntities)
    return viewer
  }

  /**
   * 添加实体
   * @param entityInfo 实体信息
   * @param callback 回调函数
   */
  addEntity(
    entityInfo: IEntityInstance,
    callback: (res: IDrawCallback) => void
  ) {
    // 提示标签
    let labelEntity: Entity | undefined
    let activeEntity: Entity | null = null
    const shapeId: string = `drawEntity_${createGuid()}`

    try {
      // 监听鼠标左键
      this.mouseHandlerManager.addLeftMouseClickHandler(
        `drawLeftClick_${this.guid}`,
        ({ screenPosition }) => {
          // 贴地坐标or空间坐标
          const position
            = screenPosition
              && MathUtils.getSurfaceCartesian3(this.viewer, screenPosition)

          // 单击开始绘制
          if (!position) return
          if (!defined(position)) return

          if (activeEntity) {
            activeEntity.position = new ConstantPositionProperty(position)
          } else {
            // 创建实体
            activeEntity = this.createEntity(
              shapeId,
              position.clone(),
              entityInfo,
              true
            )

            if (!activeEntity) return
            if (!defined(activeEntity)) return
            this.drawEntities.entities.add(activeEntity)
          }
        }
      )

      // 鼠标移动事件回调处理
      const throttle = _.throttle((screenPosition: Cartesian2) => {
        // 贴地坐标or空间坐标
        const position
          = screenPosition
            && MathUtils.getSurfaceCartesian3(this.viewer, screenPosition)

        // 若无有效坐标
        if (!position) return
        // 绘制移动实体
        if (!defined(position)) return

        if (labelEntity) {
          labelEntity.position = new ConstantPositionProperty(position)
        } else {
          labelEntity = this.createLabel(createGuid(), position, "左键标绘, 右键保存")
          this.viewer.entities.add(labelEntity)
        }
      }, 350)

      // 监听鼠标移动事件
      this.mouseHandlerManager.addMouseMoveHandler(
        `drawMouseMove_${this.guid}`,
        ({ screenPosition }) => {
          // 频繁触发
          // 节流处理
          screenPosition && throttle(screenPosition)
        }
      )

      // 监听鼠标右键事件
      this.mouseHandlerManager.addRightMouseClickHandler(
        `drawRightClick_${this.guid}`,
        ({ screenPosition }) => {
          // 移除左、右键单击，鼠标移动事件
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawLeftClick_${this.guid}`
          )
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawMouseMove_${this.guid}`
          )
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawRightClick_${this.guid}`
          )

          let position
            = activeEntity
              && activeEntity.position
              && activeEntity.position.getValue(JulianDate.now())

          // 删除提示标签
          labelEntity && this.viewer.entities.removeById(labelEntity.id)
          if (activeEntity && position) {
            activeEntity.point.show = false
            position
            && callback({
              id: shapeId,
              position
            })
          } else {
            callback({
              id: shapeId,
              position,
              result: false
            })
          }

          activeEntity = null
        }
      )
    } catch (error) {
      console.error("addEntity:", error)
    }
  }

  /**
   * 创建随鼠标移动的标签
   */
  createLabel(id: string, position: Cartesian3, text: string) {
    const shape = new Entity({
      id,
      name: "drawLabel",
      position,
      label: {
        text,
        fillColor: Color.WHITE,
        showBackground: true,
        backgroundColor: Color.fromCssColorString("rgba(22, 171, 216, 0.5)"),
        font: "14px sans-serif",
        horizontalOrigin: HorizontalOrigin.LEFT,
        pixelOffset: new Cartesian2(10, 0)
      }
    })
    return shape
  }

  /**
   * 创建实体
   * @param id
   * @param position
   * @param entityInfo
   * @returns
   */
  createEntity(
    id = createGuid(),
    position: Cartesian3,
    entityInfo: IEntityInstance,
    isActive: boolean
  ): Entity | null {
    let outLineOpacity = 0.035
    let o = false
    const shape
      = position
        && entityInfo
        && new Entity({
          id: `${id}`,
          name: "drawInstance",
          position,
          point: {
            show: isActive,
            pixelSize: 40,
            color: Color.WHITE.withAlpha(0),
            outlineWidth: new CallbackProperty(() => {
              return 5
            }, false),
            outlineColor: new CallbackProperty(() => {
              return (
                o
                  ? ((outLineOpacity -= 0.035),
                    outLineOpacity <= 0 && (o = false))
                  : ((outLineOpacity = 0.7), (o = true)),
                Color.fromCssColorString("#fff").withAlpha(outLineOpacity)
              )
            }, false)
          },
          billboard: {
            color: Color.fromCssColorString(entityInfo.basicInfo.sideColor),
            // image: `/assets/scenario/images/red/${entityInfo.entityTypeObj?.kind}-${entityInfo.entityTypeObj?.domain}-${entityInfo.entityTypeObj?.category}.png`,
            image: `/assets/scenario/${entityInfo.entityTypeObj?.kind}-${entityInfo.entityTypeObj?.domain}-${entityInfo.entityTypeObj?.category}.svg`
          },
          label: {
            text: entityInfo.basicInfo.entityName,
            scale: 0.4,
            fillColor: Color.fromCssColorString(entityInfo.basicInfo.sideColor),
            outlineColor: Color.WHITE,
            outlineWidth: 1,
            style: LabelStyle.FILL_AND_OUTLINE,
            pixelOffset: new Cartesian2(0.0, 25.0)
          }
        })

    return shape || null
  }

  /**
   * 初始添加实体
   * @param entityInfo
   * @param callback
   * @returns
   */
  initAddEntity(
    entityInfo: IEntityDetail,
    callback: (res: IDrawCallback) => void
  ) {
    if (!(entityInfo.basicInfo.longitude && entityInfo.basicInfo.latitude)) {
      return
    }
    // 贴地坐标or空间坐标
    const position = MathUtils.gcsToCartesian3({
      longitude: entityInfo.basicInfo.longitude,
      latitude: entityInfo.basicInfo.latitude,
      height: entityInfo.basicInfo.height
    })
    const id = createGuid()

    const info: IEntityInstance = {
      cesiumPosition: position,
      cesiumId: id,
      ...entityInfo
    }

    // 创建实体
    const entity = this.createEntity(id, position.clone(), info, false)

    if (!entity) return
    if (!defined(entity)) return

    this.drawEntities.entities.add(entity)

    callback({ id, position })
  }

  /**
   * 根据id获取实体
   * @param id
   */
  getById(id) {
    return this.drawEntities.entities.getById(id)
  }

  /**
   * 根据id更新标绘
   */
  updateById(
    id,
    { entityName, sideColor, longitude, latitude, height },
    callback: (res: IDrawCallback) => void
  ) {
    const entity = this.drawEntities.entities.getById(id)

    // 贴地坐标or空间坐标
    const position = MathUtils.gcsToCartesian3({
      longitude,
      latitude,
      height
    })

    if (entity && entity.label && entity.billboard) {
      entity.label.text = entityName
      entity.label.fillColor = new ConstantProperty(
        Color.fromCssColorString(sideColor)
      )
      entity.billboard.color = new ConstantProperty(
        Color.fromCssColorString(sideColor)
      )
      entity.position = new ConstantPositionProperty(position)
    }

    callback({ id, position })
  }

  /**
   * 根据id清楚标绘
   */
  clearById(id) {
    this.drawEntities.entities.removeById(id)
  }

  /**
   * 清除标绘
   */
  clearAll() {
    this.drawEntities.entities.removeAll()
  }

  /**
   * 编辑实体位置
   * @param id 实体id
   * @param drawingType 类型
   * @param positions 坐标
   * @param callback
   * @returns
   */
  editDrawEntity(
    id: string,
    position: Cartesian3,
    callback: (res: IDrawCallback) => void
  ) {
    // 编辑的实体
    const drawEntity = this.drawEntities.entities.getById(id)
    // 移动的点
    let activeEntity: Entity | undefined
    // 提示标签
    let labelEntity: Entity | undefined

    this.updateActiveEntity(drawEntity, position, true)

    try {
      // 监听鼠标左键
      this.mouseHandlerManager.addLeftMouseDownHandler(
        `drawLeftDown_${this.guid}`,
        ({ screenPosition }: { screenPosition: Cartesian2 }) => {
          activeEntity = this.viewer.scene.pick(screenPosition).id

          if (!defined(activeEntity)) return

          this.viewer.container.style.cursor = "pointer"

          if (activeEntity?.name === "drawInstance") {
            // 设置地图不可拖拽
            this.viewer.scene.screenSpaceCameraController.enableRotate = false
          }
        }
      )

      // 鼠标移动事件回调处理
      // 移除上一个实体，添加新实体
      const throttle = _.throttle((screenPosition: Cartesian2) => {
        // 贴地坐标or空间坐标
        const position
          = screenPosition
            && MathUtils.getSurfaceCartesian3(this.viewer, screenPosition)

        // 若无有效坐标
        if (!position) return
        // 绘制移动实体
        if (!defined(position)) return

        if (labelEntity) {
          labelEntity.position = new ConstantPositionProperty(position)
        } else {
          labelEntity = this.createLabel(createGuid(), position, "左键按下移动，右键保存")
          this.viewer.entities.add(labelEntity)
        }

        if (!defined(activeEntity)) return
        if (activeEntity && activeEntity.name !== "drawInstance") return

        // 更新实时位置
        activeEntity
        && (activeEntity.position = new ConstantPositionProperty(position))
      }, 350)

      // 监听鼠标移动事件
      this.mouseHandlerManager.addMouseMoveHandler(
        `drawMouseMove_${this.guid}`,
        ({ screenPosition }) => {
          // 频繁触发
          // 节流处理
          screenPosition && throttle(screenPosition)
        }
      )

      // 监听鼠标抬起事件
      this.mouseHandlerManager.addLeftMouseUpHandler(
        `drawLeftUp_${this.guid}`,
        ({ screenPosition }) => {
          activeEntity = undefined
          this.viewer.container.style.cursor = "default"
        }
      )

      // 监听鼠标抬起事件
      this.mouseHandlerManager.addRightMouseClickHandler(
        `drawRightClick_${this.guid}`,
        ({ screenPosition }) => {
          // 移除左按下、右键单击，鼠标移动事件
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawLeftUp_${this.guid}`
          )
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawLeftDown_${this.guid}`
          )
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawMouseMove_${this.guid}`
          )
          this.mouseHandlerManager.destroyHandlerByKey(
            `drawRightClick_${this.guid}`
          )

          const positions: Cartesian3[] = []
          this.viewer.scene.screenSpaceCameraController.enableRotate = true

          let pos
            = drawEntity
              && drawEntity.position
              && drawEntity.position.getValue(JulianDate.now())
          pos && positions.push(pos)

          pos && this.updateActiveEntity(drawEntity, pos, false)
          // 删除提示标签
          labelEntity && this.viewer.entities.removeById(labelEntity.id)

          callback({
            id,
            position: positions
          })
        }
      )
    } catch (error) {
      console.error("drawManager:", error)
    }
  }

  /**
   * @descripttion: 编辑点
   * @param entity 点实体
   * @param positions 坐标
   * @param isActive
   * @returns
   * @author: ssr
   */
  updateActiveEntity(
    entity: Entity | undefined,
    position: Cartesian3,
    isActive = false
  ) {
    if (!entity) return
    if (!entity.point) return

    entity.point.show = new ConstantProperty(isActive)
    entity.position = new ConstantPositionProperty(position)
  }
}
